#include "Camera.hpp"

#include "UserInterface.hpp"
#include "Context.hpp"
#include "Scene.hpp"
#include "Player.hpp"

#include <glm/gtx/matrix_interpolation.hpp>

#define CONAN 0.05f
#define PI 3.14

Camera::Camera()
  : m_viewTransform(vec3(0.0f, -5.0f, 0.0f), vec3(0.0f, 135.0f, 0.0f)),
    m_projectionMatrix(1.0f),
    m_fovy(50.0f),
    m_near(0.1f),
    m_far(1000.0f)
{
  int w = glutGet(GLUT_WINDOW_WIDTH);
  int h = glutGet(GLUT_WINDOW_HEIGHT);
  
  m_projectionMatrix = glm::perspective(m_fovy,
                                        float(w) / float(h),
                                        m_near, m_far);
  
}

void Camera::updateView()
{
    
  UIState &state = UserInterface::g_state;
  vec3 translation(0.0f, 0.0f, 0.0f);
  vec3 rotation(0.0f, 0.0f, 0.0f);
  
  mat4 finalModel, oldModel, newModel;
  Transform fTr, oTr;
  vec3 pos, camPos, newVec;
  
  switch(state.m_lights) {
    
    case 1:
      newModel = g_context.getPlayer()->header();
      newModel = glm::rotate(newModel, 180.0f, vec3(0.0f, 1.0f, 0.0f));
      newModel = glm::translate(newModel, vec3(0.0f, 0.1f, 0.5f));
      newModel = glm::inverse(newModel);
      m_viewTransform.setModelMatrix(newModel);

      break;
    case 0:
      
      //getting old position
      oldModel = glm::inverse(m_viewTransform.getModelMatrix());
      oTr = Transform(oldModel);
      
      m_viewTransform.setModelMatrix(lakitu(oTr.getTranslation()));

      break;
    case 2: 

      translation.z =  static_cast<float>(state.m_forwardMotion)   * 1.0f;
      translation.x = -static_cast<float>(state.m_sidewaysMotion)  * 1.0f;
      
      rotation.x = -static_cast<float>(state.m_pitch)              * 1.0f;
      rotation.y = -static_cast<float>(state.m_yaw)                * 1.0f;
      
      m_viewTransform.transform(translation, rotation);
      break;
  }
  


  //PRINT(m_viewTransform.getModelMatrix());
}

mat4 Camera::lakitu(const vec3 posPrev) {
  
  vec3 pos;
  float rot;
  
  if(g_context.getPlayer()->m_segway) {
    pos = g_context.getSegway()->m_pos;
    rot = 180.0f+g_context.getSegway()->m_rot;
  } else {
    pos = g_context.getPlayer()->m_pos;
    rot = 180.0f+g_context.getPlayer()->m_rot;
  }
  
  vec3 laksa;
  pos.y += 1.5f;
  
  float i = 1.0f;
  
  do {
    
    laksa = pos;
    
    laksa.x += sin(rot*PI/180)*i;
    laksa.z += cos(rot*PI/180)*i;
  
    float g = g_context.getHeight(laksa.x,laksa.z);
  
    if(laksa.y <= g);
      laksa.y = g;
    laksa.y += 6.0f;
    
    i = i+1.0f;
    if(i>9.0f)
      break;
  
  } while(g_context.boundcheck( laksa + vec3(sin(rot*PI/180),0.0f,cos(rot*PI/180)) ));
  
  laksa = (1.0f-CONAN) * posPrev + CONAN * laksa;
  return glm::lookAt(laksa, pos, vec3(0.0f,1.0f,0.0f));
  
}

void Camera::updateProjection(int width, int height)
{
  m_projectionMatrix = glm::perspective(m_fovy,
                                        float(width) / float(height),
                                        m_near, m_far);
}

glm::mat4 Camera::getViewMatrix()
{  
  return m_viewTransform.getModelMatrix();
}

glm::mat4 Camera::getProjectionMatrix()
{
  return m_projectionMatrix;
}

